import java.io.FileReader;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.ArrayList;

/**
 * @correspondence dictionary = library
 * @convention |dictionary| >= 0, 
 * 				(for all i : 0 <= i < |dictionary| : dictionary[i].length()=5 and
 * 				dictionary[i] contains only unique letters)
 * @author Yao Wang
 * 
 */
public class Dictionary implements AbstractDictionary {
	/**
	 * Allowed letter length.
	 */
	private static final int WORDLENGTH = 5;
	
	/**
	 * Stores the list of words contained in this class.
	 */
	private ArrayList<String> dictionary = new ArrayList<String>();


	/**
	 * Constructor that takes a filename argument. Reads in all the words from
	 * the file. If the word meets validity criteria then add it to the dictionary.
	 * 
	 * @param file source file to get words from
	 * @throws FileNotFoundException if the dictionary file cannot be loaded
	 */
	public Dictionary(String file) throws FileNotFoundException {
		int i = 0;
		Scanner source = null;

		// Check if the source file exists in the right directory

		source = new Scanner(new FileReader(file));
	

		// Read in data from the source file
		while (source.hasNextLine()) {
			String token = source.nextLine();
			try {
				if (isValid(token)) {
					dictionary.add(token.toLowerCase());
					i++;
				} 
			} catch (WordException e) {
				e.getCause(); // Suppress WordExceptions
			}
		}
	}

	/**
	 * @param word
	 *            target word to be checked
	 * @return true if word contains only letters and is of desired length false
	 *         if else
	 * @throws WordException if word is not valid
	 */
	private boolean isValid(String word) throws WordException {
		boolean length = (word.length() == WORDLENGTH);
		if (!length) {
			throw new WordException(WordProblem.WrongLength);
		}
		boolean alphanum = word.matches("^[a-zA-Z]+$");
		if (!alphanum) {
			throw new WordException(WordProblem.NotOnlyAlpha);
		}
		boolean nodupletters = true;
		for (int i = 0; i < word.length(); i++) {
			char letter = word.charAt(i);
			nodupletters = nodupletters
					&& (word.indexOf(letter) == word.lastIndexOf(letter));
		}
		if (!nodupletters) {
			throw new WordException(WordProblem.DupLetters);
		}
		return length && alphanum && nodupletters;
	}

	/**
	 * Compares with two words, and return the number of letters they share.
	 * @throws WordException if not in dictionary
	 * @return int number of common characters
	 * @param word1 first word
	 * @param word2 second word for comparison
	 */
	public int compareWords(String word1, String word2) throws WordException {
		int shared = 0, i = 0;
		word1 = word1.toLowerCase();
		word2 = word2.toLowerCase();

		// Check if the words are in the valid format			
		if (!containsWord(word1)) {
			throw (new WordException(WordProblem.NotInDict));
		} else if (!containsWord(word2)) {
			throw (new WordException(WordProblem.NotInDict));
		} else if (isValid(word1) && isValid(word2)) {
			while (i < WORDLENGTH) {
				CharSequence temp = word1.subSequence(i, i + 1);
				if (word2.contains(temp)) {
					shared++;
				}
				i++;
			}
		}
		return shared;
	}

	/**
	 * Check if a target word is in the dictionary class. 
	 * 
	 * @return whether dictionary contains word
	 * @param word value of interest for the dictionary
	 */
	public boolean containsWord(String word) {
		word = word.toLowerCase();
		return dictionary.contains(word);
	}

	/**
	 * Returns the number of words in the dictionary.
	 * 
	 * @return size of dictionary
	 */
	public int size() {
		return dictionary.size();
	}
	
	/**
	 * Returns a copy of the word at the specified index in the dictionary.
	 * @return String the word from the dictionary at specific index.
	 * @param i index of word wanted
	 */
	public String getWord(int i) {
		return dictionary.get(i);
	}
}
